+3  A: 

The default ASP.NET MVC 2 template of Visual Studio includes the exact validation attribute you need. Pasted from AccountModels.cs file :

[AttributeUsage(AttributeTargets.Class, 
    AllowMultiple = true, Inherited = true)]
public sealed class PropertiesMustMatchAttribute : ValidationAttribute {
    private const string _defaultErrorMessage = 
        "'{0}' and '{1}' do not match.";
    private readonly object _typeId = new object();

    public PropertiesMustMatchAttribute(string originalProperty, 
        string confirmProperty)
        : base(_defaultErrorMessage) {
        OriginalProperty = originalProperty;
        ConfirmProperty = confirmProperty;
    }

    public string ConfirmProperty { get; private set; }
    public string OriginalProperty { get; private set; }

    public override object TypeId {
        get {
            return _typeId;
        }
    }

    public override string FormatErrorMessage(string name) {
        return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString,
            OriginalProperty, ConfirmProperty);
    }

    public override bool IsValid(object value) {
        PropertyDescriptorCollection properties = 
           TypeDescriptor.GetProperties(value);
        object originalValue = properties.Find(OriginalProperty, 
            true /* ignoreCase */).GetValue(value);
        object confirmValue = properties.Find(ConfirmProperty, 
            true /* ignoreCase */).GetValue(value);
        return Object.Equals(originalValue, confirmValue);
    }
}

How to use :

[PropertiesMustMatch("Password", "ConfirmPassword", 
    ErrorMessage = "The password and confirmation password do not match.")]
class NewUser {
    [Required]
    [DataType(DataType.Password)]
    [DisplayName("Password")]
    public string Password { get; set; }
    [Required]
    [DataType(DataType.Password)]
    [DisplayName("Confirm password")]
    public string ConfirmPassword { get; set; }
}
çağdaş
The only problem I can see with this is, when two properties of the Model (class in this case), aren't equal, it doesn't denote the specific Properties as containing errors, like it does for [Required] and <%=Html.ValidationMessageFor(m => m.Password1) %>
CodeMonkey
@CodeMonkey, I see. Though I'm not sure if there's an elegant solution to make it work the other way, using model binding. After all, this is technically a class-level validation. If you **must** add the errors to the properties instead, then maybe checking the two values in the controller after the binding would be the quickest solution (though not the most elegant).
çağdaş
In the MVC 2 version the Html.ValidationSummary helper method can now display Model-Level only errors
murki